bitkeeper revision 1.727 (402fc94bvWV4StLy1t8mm8tbdu4SAQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 15 Feb 2004 19:32:27 +0000 (19:32 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 15 Feb 2004 19:32:27 +0000 (19:32 +0000)
memory.c, keyhandler.c:
  Include page-frame audit code in debug builds.

xen/common/keyhandler.c
xen/common/memory.c

index ec0eee2af6de02b4fadf058fb7c2f9c3c5836a0d..0a99969113243519d4b38ec47523f02a5753b959 100644 (file)
@@ -131,6 +131,10 @@ extern void perfc_reset (u_char key, void *dev_id, struct pt_regs *regs);
 extern void dump_runq(u_char key, void *dev_id, struct pt_regs *regs);
 extern void print_sched_histo(u_char key, void *dev_id, struct pt_regs *regs);
 extern void reset_sched_histo(u_char key, void *dev_id, struct pt_regs *regs);
+#ifndef NDEBUG
+void reaudit_pages(u_char key, void *dev_id, struct pt_regs *regs);
+void audit_all_pages(u_char key, void *dev_id, struct pt_regs *regs);
+#endif
 
 
 void initialize_keytable() 
@@ -152,5 +156,8 @@ void initialize_keytable()
     add_key_handler('r', dump_runq,      "dump run queues");
     add_key_handler('B', kill_dom0,      "reboot machine gracefully"); 
     add_key_handler('R', halt_machine,   "reboot machine ungracefully"); 
-    return; 
+#ifndef NDEBUG
+    add_key_handler('m', reaudit_pages, "re-audit pages");
+    add_key_handler('M', audit_all_pages, "audit all pages");
+#endif
 }
index cd643b26869b4454239cbe360f50805257c8d42d..37f6ec3294f96728f5ddc4889718ef26f00866c2 100644 (file)
@@ -1100,3 +1100,193 @@ int do_update_va_mapping(unsigned long page_nr,
     
     return err;
 }
+
+
+#ifndef NDEBUG
+/*
+ * below are various memory debugging functions: 
+ * __audit_page():    prints out all the ptes a pages is listed in
+ * audit_page():      in addition maintains a history of audited pages
+ * reaudit_pages():   re-audit previously audited pages
+ * audit_all_pages(): check the ref-count for all leaf pages
+ *                    also checks for zombie pages
+ * 
+ * reaudit_page() and audit_all_pages() are designed to be
+ * keyhandler functions so that they can be easily invoked from the console.
+ */
+
+
+/*
+ * prints out all the pt's a page is listed in
+ */
+void __audit_page(unsigned long pfn) {
+    unsigned long     i, j;
+    struct pfn_info  *page;
+    unsigned long     page_addr;
+    l1_pgentry_t     *pl1e, l1e;
+    
+    page = &frame_table[pfn];
+    page_addr = pfn << PAGE_SHIFT;
+
+    printk("audit page: pfn=%lx info: cf=%lx tf=%lx ts=%lx dom=%lx\n", pfn,
+           page->count_and_flags, page->type_and_flags,
+           page->tlbflush_timestamp, (unsigned long)page->u.domain);
+
+    /* walk the frame table */
+    for ( i = 0; i < max_page; i++ )
+    {
+        if ( (frame_table[i].count_and_flags & PGC_count_mask) == 0 )
+            continue;
+        if ( (frame_table[i].count_and_flags & PGC_zombie) != 0 )
+            continue;
+
+        /* check if entry is a page table (L1 page table) and in use */
+        if ( ((frame_table[i].type_and_flags & PGT_type_mask) ==
+              PGT_l1_page_table) &&
+             ((frame_table[i].type_and_flags & PGT_count_mask) != 0) )
+        {
+            pl1e = map_domain_mem(i << PAGE_SHIFT);
+
+            /* scan page table for page to audit */
+            for ( j=0; j < ENTRIES_PER_L1_PAGETABLE; j++  )
+            {
+                l1e = pl1e[j];
+                if ( l1_pgentry_empty(l1e) )
+                    continue;
+                if ( l1_pgentry_to_pagenr(l1e) == pfn )
+                {
+                    printk("  pte_pfn=%06lx cf=%08lx tf=%08lx dom=%08lx\n", 
+                           i, frame_table[i].count_and_flags,
+                           frame_table[i].type_and_flags,
+                           (unsigned long)frame_table[i].u.domain);
+                    printk("    pte_idx=%03lx *pte_idx=%08lx\n", 
+                           j, l1_pgentry_val(l1e));
+                }
+            }
+            unmap_domain_mem(pl1e);
+        }
+    }
+
+}
+
+/*
+ * audit a page and keep a history of audited pfns
+ */
+#define LASTPAGES_SIZE 128
+static long last_pages[LASTPAGES_SIZE];
+static int  last_pages_idx = 0;
+void audit_page(unsigned long pfn)
+{
+    unsigned long     i;
+
+    cli();
+    __audit_page(pfn);
+    sti();
+    /* add pfn to last_pages cache if is not already present */
+    for ( i = 0; i < LASTPAGES_SIZE; i++ )
+        if ( last_pages[i] == pfn )
+            return;
+
+    /* new entry */
+    last_pages[last_pages_idx++] = pfn;
+    if ( last_pages_idx >= LASTPAGES_SIZE ) 
+        last_pages_idx = 0;
+
+}
+
+/*
+ * re-audit previously audited pages
+ */
+void reaudit_pages(u_char key, void *dev_id, struct pt_regs *regs)
+{
+    int i;
+
+    printk("Dumping audited pages\n");
+
+    for ( i = 0; i < LASTPAGES_SIZE; i++ )
+        if ( last_pages[i] != 0 )
+            __audit_page(last_pages[i]);
+}
+
+/*
+ * do various checks on all pages.
+ * Currently:
+ * - check for zombie pages
+ * - check for pages with corrupt ref-count
+ * Interrupts are diabled completely. use with care.
+ */
+void audit_all_pages (u_char key, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long     i, j, k;
+    unsigned long     ref_count;
+    l1_pgentry_t     *pl1e, l1e;
+
+    printk("audit_all_pages\n");
+
+    cli();
+    
+    /* walk the frame table */
+    for ( i = 0; i < max_page; i++ )
+    {
+
+        /* check for zombies */
+        if ( ((frame_table[i].count_and_flags & PGC_count_mask) != 0) &&
+             ((frame_table[i].count_and_flags & PGC_zombie) != 0) )
+        { 
+            printk("zombie: pfn=%08lx cf=%08lx tf=%08lx dom=%08lx\n", 
+                   i, frame_table[i].count_and_flags,
+                   frame_table[i].type_and_flags,
+                   (unsigned long)frame_table[i].u.domain);
+        }
+
+        /* check ref count for leaf pages */
+        if ( ((frame_table[i].type_and_flags & PGT_type_mask) ==
+               PGT_writeable_page) )
+        {
+            ref_count = 0;
+
+            /* find page tables */
+            for ( j = 0; j < max_page; j++ )
+            {
+                if ( ((frame_table[j].type_and_flags & PGT_type_mask) ==
+                      PGT_l1_page_table) &&
+                     ((frame_table[j].type_and_flags & PGT_count_mask) != 0) )
+                {
+                    pl1e = map_domain_mem(j << PAGE_SHIFT);
+
+                    /* scan page table for page to audit */
+                    for ( k=0; k < ENTRIES_PER_L1_PAGETABLE; k++  )
+                    {
+                        l1e = pl1e[k];
+                        if ( l1_pgentry_empty(l1e) )
+                            continue;
+                        if ( l1_pgentry_to_pagenr(l1e) == i )
+                        {
+                            ref_count++;
+                            /* page is in pagetable */
+                        }
+                    }
+                    unmap_domain_mem(pl1e);
+                }
+
+            }
+
+            /* check for PGC_ALLOCATED */
+            if ( (frame_table[i].count_and_flags & PGC_allocated) != 0 )
+                ref_count++;
+
+            if ( (frame_table[i].count_and_flags & PGC_count_mask) 
+                 != ref_count )
+            {
+                printk("refcount error: pfn=%06lx cf=%08lx refcount=%lx\n",
+                       i, frame_table[i].count_and_flags, ref_count);
+                __audit_page(i);
+                printk("\n");
+            }
+        } /* ref count error */
+    }
+    sti();
+    
+}
+
+#endif /* NDEBUG */